package com.flynn.rock.crm.schedule;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.flynn.rock.crm.convert.AbstractCustomerConvert;
import com.flynn.rock.crm.entity.customer.CustomerEntity;
import com.flynn.rock.crm.entity.customer.ReceiveCustomerEntity;
import com.flynn.rock.crm.entity.employee.EmployeeEntity;
import com.flynn.rock.crm.model.AutoDispatchOrderConfigDto;
import com.flynn.rock.crm.model.ThirdPartyCustomerInfo;
import com.flynn.rock.crm.repository.CrmConfigRepository;
import com.flynn.rock.crm.repository.customer.CustomerOperateRecordRepository;
import com.flynn.rock.crm.repository.customer.CustomerOrderRepository;
import com.flynn.rock.crm.repository.customer.CustomerRepository;
import com.flynn.rock.crm.repository.customer.ReceiveCustomerRepository;
import com.flynn.rock.crm.repository.employee.EmployeeRepository;
import com.flynn.rock.crm.service.customer.ThirdPartyCustomerService;
import com.flynn.rock.enums.customer.CustomerCreateType;
import com.flynn.rock.enums.customer.CustomerOrderStatus;
import com.flynn.rock.enums.customer.CustomerStatus;
import com.flynn.rock.enums.customer.ReceiveStatus;
import com.flynn.rock.enums.system.NoIdentifierType;
import com.flynn.rock.model.dto.CustomerOperateRecordDto;
import com.flynn.rock.system.api.ISysMessageApi;
import com.flynn.rock.system.api.ISysNoIdentifierApi;
import com.flynn.rock.system.model.dto.SaveMessageDto;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;

@Slf4j
@Component
public class CrmScheduled {

    private static final List<CharSequence> MONEY_UNIT = Arrays.asList("万", "w", "W");

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN);

    private static final Queue<EmployeeEntity> ENABLE_RECEIVE_EMPLOYEE_QUEUE = new LinkedList<>();

    @Resource
    private ThirdPartyCustomerService thirdPartyCustomerService;

    @Resource
    private ReceiveCustomerRepository receiveCustomerRepository;

    @Resource
    private CrmConfigRepository crmConfigRepository;

    @Resource
    private EmployeeRepository employeeRepository;

    @Resource
    private CustomerRepository customerRepository;

    @Resource
    private CustomerOrderRepository customerOrderRepository;

    @Resource
    private CustomerOperateRecordRepository customerOperateRecordRepository;

    @Resource
    private ISysNoIdentifierApi sysNoIdentifierApi;

    @Resource
    private ISysMessageApi sysMessageApi;


    @Scheduled(cron = "0 0/30 * * * ?")
    public void pullThirdPartyCustomerInfos() {
        Optional<AutoDispatchOrderConfigDto> configDtoOptional = this.getAutoDispatchOrderConfig();
        if (configDtoOptional.isEmpty()) {
            return;
        }
        AutoDispatchOrderConfigDto configDto = configDtoOptional.get();
        if (!configDto.getAutoReceive()) {
            return;
        }
        String customerInfos = thirdPartyCustomerService.pullCustomerInfos();
        if (!StringUtils.hasText(customerInfos) || !JSONUtil.isTypeJSON(customerInfos)) {
            return;
        }
        log.info("Start pull thirdParty customer infos");
        List<ThirdPartyCustomerInfo> thirdPartyCustomerInfos = this.obtainThirdPartyCustomerInfos(customerInfos);
        for (ThirdPartyCustomerInfo thirdPartyCustomerInfo : thirdPartyCustomerInfos) {
            String phone = thirdPartyCustomerInfo.getPhone();
            if (!StringUtils.hasText(phone) || Objects.nonNull(receiveCustomerRepository.findByPhone(phone))) {
                log.warn("拉取的客户电话为空，或电话已被注册，客户【{}】丢弃", thirdPartyCustomerInfo.getCustomerName());
                continue;
            }
            ReceiveCustomerEntity entity = AbstractCustomerConvert.INSTANCE.toReceiveCustomerEntity(thirdPartyCustomerInfo);
            receiveCustomerRepository.save(entity);
        }
        log.info("End pull thirdParty customer infos");
    }

    @Scheduled(cron = "0 0/5 * * * ?")
    public void autoDispatchCustomerOrder() {
        Optional<AutoDispatchOrderConfigDto> configDtoOptional = this.getAutoDispatchOrderConfig();
        if (configDtoOptional.isEmpty()) {
            return;
        }
        AutoDispatchOrderConfigDto configDto = configDtoOptional.get();
        if (!configDto.getAutoReceive() || this.isNotExecuteAutoJob(configDto)) {
            return;
        }
        log.info("Auto Dispatch Customer Order Start");
        Optional<EmployeeEntity> receiveEmployee = this.getFirstReceiveEmployee(configDto);
        receiveEmployee.ifPresent(employeeEntity -> {
            Optional<ReceiveCustomerEntity> optional = receiveCustomerRepository.findFirstByAutoCreateCustomerOrderByCreateTimeAsc(Boolean.FALSE);
            if (optional.isEmpty()) {
                log.warn("没有可分配的客户");
                return;
            }
            ReceiveCustomerEntity receiveCustomerEntity = optional.get();
            CustomerEntity customerEntity = this.builderCustomer(employeeEntity, receiveCustomerEntity);
            SaveMessageDto messageDto = this.builderSaveMessageDto(employeeEntity, customerEntity);
            customerRepository.save(customerEntity);
            sysMessageApi.saveMessage(messageDto);
            receiveCustomerRepository.updateAutoCreateCustomerState(receiveCustomerEntity.getId());
            this.removeFirstReceiveEmployee();
        });
        log.info("Auto Dispatch Customer Order End");
    }

    @Scheduled(cron = "0 0 0 * * ? ")
    public void autoNoFollowUpRecovery() {
        Optional<AutoDispatchOrderConfigDto> configDtoOptional = this.getAutoDispatchOrderConfig();
        if (configDtoOptional.isEmpty()) {
            return;
        }
        AutoDispatchOrderConfigDto configDto = configDtoOptional.get();
        if (!Boolean.TRUE.equals(configDto.getNoFollowUpRecovery()) ||
                Objects.isNull(configDto.getNoFollowUpRecoveryDay())) {
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime localDateTime = now.minusDays(configDto.getNoFollowUpRecoveryDay());
        List<CustomerEntity> customers = customerRepository.findAllByLastFollowUpTimeLessThanEqual(localDateTime);
        if (CollectionUtils.isEmpty(customers)) {
            return;
        }
        log.info("Auto NoFollowUpRecovery Start");
        for (CustomerEntity customer : customers) {
            if (Objects.isNull(customer.getFollowUpUserId())) {
                continue;
            }
            CustomerOperateRecordDto operateRecordDto = CustomerOperateRecordDto.builder()
                    .customerId(customer.getCustomerId())
                    .operateUserId(-10L)
                    .operateUserName("系统")
                    .operateTitle("超期未跟进自动转派")
                    .build();
            operateRecordDto.setOperateContent("客户 " + configDto.getNoFollowUpRecoveryDay() + "天 未跟进被系统自动放入公海");
            customer.setFollowUpUserId(null);
            customer.setFollowUpUserName(null);
            customerRepository.save(customer);
            customerOrderRepository.updateCustomerOrderStatus(customer.getCustomerId(), CustomerOrderStatus.cancelled);
            customerOperateRecordRepository.saveCustomerOperateRecord(operateRecordDto);
        }
        log.info("Auto NoFollowUpRecovery End");
    }

    public void clearEnableReceiveEmployeeCache() {
        synchronized (ENABLE_RECEIVE_EMPLOYEE_QUEUE) {
            ENABLE_RECEIVE_EMPLOYEE_QUEUE.clear();
        }
    }

    /**
     *
     * @param configDto 配置信息
     * @return false 代表执行
     */
    private boolean isNotExecuteAutoJob(AutoDispatchOrderConfigDto configDto) {
        String workStartTime = configDto.getWorkStartTime();
        String workEndTime = configDto.getWorkEndTime();
        if (StrUtil.isEmpty(workEndTime) || StrUtil.isEmpty(workStartTime)) {
            return true;
        }
        LocalDateTime now = LocalDateTime.now();
        LocalTime startTime = LocalTime.parse(workStartTime, DATE_TIME_FORMATTER);
        LocalTime endTime = LocalTime.parse(workEndTime, DATE_TIME_FORMATTER);
        LocalDateTime startLocalDateTime = LocalDateTime.of(LocalDate.from(now), startTime);
        LocalDateTime endLocalDateTime = LocalDateTime.of(LocalDate.from(now), endTime);
        return !now.isAfter(startLocalDateTime) || !now.isBefore(endLocalDateTime);
    }

    private SaveMessageDto builderSaveMessageDto(EmployeeEntity employeeEntity, CustomerEntity customerEntity) {
        SaveMessageDto messageDto = new SaveMessageDto();
        messageDto.setFromUserId(-10L);
        messageDto.setFromUsername("系统");
        messageDto.setToUserId(employeeEntity.getUserId());
        messageDto.setMessageTitle("系统分配客户通知");
        messageDto.setMessageContent("编号为" + customerEntity.getCustomerCode() + "的" +
                customerEntity.getCustomerName() + "客户由系统分配给您");
        messageDto.setMessageBusinessType("CUSTOMER");
        return messageDto;
    }

    private CustomerEntity builderCustomer(EmployeeEntity employeeEntity, ReceiveCustomerEntity receiveCustomer) {
        CustomerEntity customerEntity = AbstractCustomerConvert.INSTANCE.toCustomerEntity(receiveCustomer);
        customerEntity.setFollowUpUserId(employeeEntity.getUserId());
        customerEntity.setFollowUpUserName(employeeEntity.getRealName());
        customerEntity.setCreateUserId(-10L);
        customerEntity.setStatus(CustomerStatus.NEW_CUSTOMER);
        customerEntity.setCreateType(CustomerCreateType.automatic_create);
        customerEntity.setCustomerCode(sysNoIdentifierApi.getNoIdentifier(NoIdentifierType.CUSTOMER_CODE));
        return customerEntity;
    }

    private Optional<EmployeeEntity> getFirstReceiveEmployee(AutoDispatchOrderConfigDto config) {
        if (CollectionUtils.isEmpty(ENABLE_RECEIVE_EMPLOYEE_QUEUE)) {
            synchronized (ENABLE_RECEIVE_EMPLOYEE_QUEUE) {
                List<Long> receiveDeptIds = config.getReceiveDept();
                if (!CollectionUtils.isEmpty(receiveDeptIds)) {
                    employeeRepository.findAllByDeptIdInAndReceiveStatus(receiveDeptIds, ReceiveStatus.ENABLE)
                            .stream()
                            .sorted(Comparator.comparing(EmployeeEntity::getReceivePriority).reversed())
                            .forEach(ENABLE_RECEIVE_EMPLOYEE_QUEUE::offer);
                }
            }
        }
        return Optional.ofNullable(ENABLE_RECEIVE_EMPLOYEE_QUEUE.peek());
    }

    private void removeFirstReceiveEmployee() {
        synchronized (ENABLE_RECEIVE_EMPLOYEE_QUEUE) {
            ENABLE_RECEIVE_EMPLOYEE_QUEUE.poll();
        }
    }

    private Optional<AutoDispatchOrderConfigDto> getAutoDispatchOrderConfig() {
        return crmConfigRepository.getCrmConfigEntity(CrmConfigRepository.AutoDispatchOrderConfigKey)
                .map(entity -> JSONUtil.parseObj(entity.getConfigValue()).toBean(AutoDispatchOrderConfigDto.class));
    }

    private List<ThirdPartyCustomerInfo> obtainThirdPartyCustomerInfos(String customerInfos) {
        JSONArray dataArray = JSONUtil.parseObj(customerInfos).getJSONArray("data");
        if (Objects.isNull(dataArray) || dataArray.isEmpty()) {
            return Collections.emptyList();
        }
        return dataArray.toList(String.class).stream()
                .map(this::decodeData)
                .peek(info -> {
                    if (StrUtil.isNotBlank(info.getMoney())) {
                        String money = info.getMoney().split("-")[0];
                        if (MONEY_UNIT.stream().anyMatch(money::contains)) {
                            BigDecimal bigDecimal = new BigDecimal(money.substring(0, money.length() - 1));
                            info.setLoanLimit(bigDecimal.multiply(new BigDecimal(10000)));
                        } else {
                            log.warn("拉取的" + info.getCustomerName() + "客户,贷款额度单位错误");
                        }
                    }
                })
                .toList();
    }

    private ThirdPartyCustomerInfo decodeData(String encodeData) {
        AES aes = SecureUtil.aes("f2NGyRP2rblnRQJC".getBytes(StandardCharsets.UTF_8));
        String utf8Data = UnicodeUtil.toString(aes.decryptStr(Base64.decodeStr(encodeData)));
        return JSONUtil.parseObj(utf8Data).toBean(ThirdPartyCustomerInfo.class);
    }
}
